﻿/**********************************************************/
/* ScheidsRechter classe. */
/* 13-10-2010 - Groep 6: Scheidsrechter(Lars Mohr 0629693, Roy Mengelers 0705020, Roy Lieben 0847186, Timothy Janssen 0951986, Lars Brand 0901164 - */
/*	
/* Omschrijving:
/* Hier staat alles in wat de scheidsrechter doet.*/
/**********************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Roborally.CommonData.Enums;
using Roborally.CommonData.GlobaleTypes;


namespace Roborally.Scheidsrechter
{
    public class ScheidsRechter : IScheidsRechter
    {
        public ScheidsRechter() { }

        /// <summary>Berekend het aantal kaarten uit te delen door de spelleider a.d.h.v. schadepunten.</summary>
        /// <exception>InputParameters is null.</exception>
        /// <exception>InputParameters.Schadepunten is negatief.</exception>
        /// <param name="InputParameters.Schadepunten">Het aantal schadepunten v/d speler.</param>
        /// <returns>Het aantal uit te delen kaarten.</returns>
        public ReturnScheidsrechter VraagAantalKaarten(InputScheidsrechter InputParameters)
        {
            if (InputParameters == null) throw new Exception("InputParameters - Null reference.");
            if (InputParameters.Schadepunten < 0) throw new Exception("InputParameters.Schadepunten - Moet een positieve waarde bevatten.");

            try
            {
                ReturnScheidsrechter output = new ReturnScheidsrechter();
                if (InputParameters.Schadepunten <= 9)
                    output.AantalKaarten = 9 - InputParameters.Schadepunten;
                else
                    output.AantalKaarten = 0;
                return output;
            }
            catch (Exception e) { throw new Exception("VraagAantalKaarten - Berekenen van het aantal kaarten mislukt.", e); }
        }

        /// <summary>Sorteren van een lijst met prioriteiten van hoog naar laag.</summary>
        /// <exception>InputParameters is null.</exception>
        /// <exception>InputParameters.Prioriteiten is null.</exception>
        /// <param name="InputParameters.Prioriteiten">Ongesorteerde lijst met prioriteiten.</param>
        /// <returns>Gesorteerde lijst met prioriteiten.</returns>
        public ReturnScheidsrechter VraagVolgorde(InputScheidsrechter InputParameters)
        {
            if (InputParameters == null) throw new Exception("InputParameters - Null reference.");
            if (InputParameters.Prioriteiten == null) throw new Exception("InputParameters.Prioriteiten - Null reference.");

            try
            {
                ///
                ReturnScheidsrechter output = new ReturnScheidsrechter();
                while (InputParameters.Prioriteiten.Count > 0)
                {
                    int max = InputParameters.Prioriteiten.Max();
                    InputParameters.Prioriteiten.Remove(max);
                    output.Prioriteiten.Add(max);
                }
                return output;
            }
            catch (Exception e) { throw new Exception("InputParamters - Sorteren van de kaarten mislukt.", e); }
        }

        /// <summary>Voert een zet uit voor één robot met één kaart.</summary>
        /// <exception>InputParameters is null</exception>
        /// <exception>InputParameters.GegevensEenSpeler is null</exception>
        /// <exception>InputParameters.GegevensSpelers is null</exception>
        /// <exception>InputParameters.Kaart is null</exception>
        /// <exception>InputParameters.Kaart is geen ProgramKaart</exception>
        /// <exception>InputParameters.Bord is null</exception>
        /// <exception>InputParameters.Kaart.AantalStappen moet een positieve waarde bevatten</exception>
        /// <param name="InputParameters.GegevensEenSpeler">Huidige speler waar de zet voor uitgevoerd wordt.</param>
        /// <param name="InputParameters.GegevensSpelers">Lijst met tegenstanders.</param>
        /// <param name="InputParameters.Kaart">De kaart die gespeelt wordt.</param>
        /// <param name="InputParameters.Bord">Huidige status van het bord.</param>
        /// <returns>Nieuwe status van de speler en de tegenstanders.</returns>
        public ReturnScheidsrechter VoerZetUit(InputScheidsrechter InputParameters)
        {
            if (InputParameters == null) throw new Exception("InputParameters - Null reference.");
            if (InputParameters.GegevensEenSpeler == null) throw new Exception("InputParameters.GegevensEenSpeler - Null reference.");
            if (InputParameters.GegevensSpelers == null) throw new Exception("InputParameters.GegevensSpelers - Null reference.");
            if (InputParameters.Kaart == null) throw new Exception("InputParameters.Kaart - Null reference.");
            if (InputParameters.Kaart.GetType() != typeof(ProgramKaart)) throw new Exception("InputParameters.Kaart - Andere kaarten dan ProgramKaarten niet toegestaan.");
            if (InputParameters.Model == null) throw new Exception("InputParameter.Bord - Null reference.");

            ProgramKaart kaart = InputParameters.Kaart as ProgramKaart;
            if (kaart.AantalStappen < 0) throw new Exception("InputParameters.Kaart.AantalStappen - Moet een positieve waarde bevatten.");

            try
            {
                ReturnScheidsrechter output = new ReturnScheidsrechter();
                output.GegevensEenSpeler = InputParameters.GegevensEenSpeler.Copy();
                foreach (SpelerGegevens speler in InputParameters.GegevensSpelers)
                    output.GegevensSpelers.Add(speler.Copy());

                if (Bewegen.PositieOpBord(output.GegevensEenSpeler.Positie, InputParameters.Model))
                {
                    switch (kaart.GetSoort())
                    {
                        case KaartSoort.Backup:
                            for (int i = 0; i < kaart.AantalStappen; i++)
                                Bewegen.ZetStap(output.GegevensSpelers, output.GegevensEenSpeler, Bewegen.TegenovergesteldeRichting(output.GegevensEenSpeler.Richting), InputParameters.Model);
                            break;
                        case KaartSoort.Vooruit:
                            for (int i = 0; i < kaart.AantalStappen; i++)
                                Bewegen.ZetStap(output.GegevensSpelers, output.GegevensEenSpeler, output.GegevensEenSpeler.Richting, InputParameters.Model);
                            break;
                        case KaartSoort.RechtsDraaien:
                            Bewegen.DraaiSpelerWest(output.GegevensEenSpeler);
                            break;
                        case KaartSoort.LinksDraaien:
                            Bewegen.DraaiSpelerOost(output.GegevensEenSpeler);
                            break;
                        case KaartSoort.Uturn:
                            Bewegen.DraaiSpelerWest(output.GegevensEenSpeler);
                            Bewegen.DraaiSpelerWest(output.GegevensEenSpeler);
                            break;
                    }
                }
                return output;
            }
            catch (Exception e)
            {
                Console.WriteLine("VoerZetUit - Uitvoeren van de zet mislukt: " + e.ToString());
                throw new Exception("VoerZetUit - Uitvoeren van de zet mislukt.", e);
            }
        }

        public ReturnScheidsrechter Loopbanden(InputScheidsrechter InputParameters)
        {
            return LoopbandenFase.LoopBanden(InputParameters);
        }

        /// <summary>
        /// Voert alle draaischijven uit op het bord.
        /// </summary>
        /// <exception>InputParameters is null.</exception>
        /// <exception>InputParameters.Bord is null.</exception>
        /// <param name="InputParameters.Bord">Huidige status van het bord.</param>
        /// <param name="InputParameters.GegevensSpelers">Alle spelers op het bord.</param>
        /// <returns>Nieuwe status van het bord en de spelers.</returns>
        public ReturnScheidsrechter Draaien(InputScheidsrechter InputParameters)
        {
            if (InputParameters == null) throw new Exception("InputParameters - Null reference."); // Deze exception komt wanneer niks wordt meegegeven.
            if (InputParameters.Model == null) throw new Exception("InputParameters.Bord - Null reference."); //

            try
            {
                ReturnScheidsrechter output = new ReturnScheidsrechter();
                foreach (SpelerGegevens gegevensSpeler in InputParameters.GegevensSpelers)
                    output.GegevensSpelers.Add(gegevensSpeler.Copy());

                foreach (SpelerGegevens speler in output.GegevensSpelers)
                {
                    if (Bewegen.PositieOpBord(speler.Positie, InputParameters.Model) && InputParameters.Model.Vakken[speler.Positie.X, speler.Positie.Y].KrijgType() == VakType.Draaischijf)
                    {
                        switch (InputParameters.Model.Vakken[speler.Positie.X, speler.Positie.Y].KrijgDraairichting())
                        {
                            case DraaiRichting.Links:
                                Bewegen.DraaiSpelerOost(speler);
                                break;
                            default:
                                Bewegen.DraaiSpelerWest(speler);
                                break;
                        }
                    }
                }
                return output;
            }
            catch (Exception e) { throw new Exception("Draaischijven - Het Uitvoeren van de draaischijven is mislukt.", e); }
        }

        /// <summary>
        /// Methode nog niet geimplementeerd.
        /// <exception>Not Implemented</exception>
        /// </summary>
        public ReturnScheidsrechter Pushers(InputScheidsrechter InputParameters)
        {
            ReturnScheidsrechter output = new ReturnScheidsrechter();
            output.GegevensSpelers = InputParameters.GegevensSpelers;
            return output;

        }

        /// <summary>
        /// Methode nog niet geimplementeerd.
        /// <exception>Not Implemented</exception>
        /// </summary>
        public ReturnScheidsrechter Lasers(InputScheidsrechter InputParameters)
        {
            ReturnScheidsrechter output = new ReturnScheidsrechter();
            output.GegevensSpelers = InputParameters.GegevensSpelers;
            return output;
        }


        /// <summary>Controleerd voor elke speler of een checkpoint behaald is.</summary>
        /// <exception>InputParameters is null.</exception>
        /// <exception>InputParameters.Bord is null.</exception>
        /// <exception>InputParameters.GegevensSpelers is null</exception>
        /// <exception>InputParameters.GegevensSpelers[].LaatstBehaaldeVlag Moet een positieve waarde bevatten.</exception>
        /// <param name="InputParameters.Bord">Huidige status van het bord.</param>
        /// <param name="InputParameters.GegevensSpelers">Lijst van spelers.</param>
        /// <returns>Lijst met geupdate speler status. Speler heeft vlagbehaald en speler beginpositie wordt checkpoint?</returns>
        public ReturnScheidsrechter Eind(InputScheidsrechter InputParameters)
        {
            if (InputParameters == null) throw new Exception("InputParameters - Null reference.");
            if (InputParameters.Model == null) throw new Exception("InputParameters.Bord - Null reference.");
            if (InputParameters.GegevensSpelers == null) throw new Exception("InputParameters.GegevensSpelers - Null reference. ");

            try
            {
                ReturnScheidsrechter output = new ReturnScheidsrechter();
                foreach (SpelerGegevens gegevens in InputParameters.GegevensSpelers)
                    output.GegevensSpelers.Add(gegevens.Copy());

                foreach (SpelerGegevens speler in output.GegevensSpelers)
                {
                    if (speler.LaatstBehaaldeVlag < 0) throw new Exception("SpelerGegevens.LaatstBehaaldeVlag - Moet een positieve waarde bevatten.");

                    VakType type = InputParameters.Model.Vakken[speler.Positie.X, speler.Positie.Y].KrijgType();
                    if (type == VakType.Checkpoint)
                    {
                        IVak Vakje = InputParameters.Model.Vakken[speler.Positie.X, speler.Positie.Y]; ;
                        speler.VlagBehaald = (speler.LaatstBehaaldeVlag + 1 == Vakje.CheckpointNummer());
                        speler.BeginPositie = speler.VlagBehaald;
                    }
                }
                return output;
            }
            catch (Exception e) { throw new Exception("Eindfase - Uitvoeren van berekening positie vakjargon mislukt", e); }
        }

        /// <summary>
        /// Opvragen van de timertijd.
        /// </summary>
        /// <returns>De timertijd.</returns>
        public int VraagTimerTijd()
        {
            return 30;
        }
    }
}
